Pong Game Implementation in Python

October 3, 2024
You said:
You are tasked with writing a pong game that can be run fully with a base version of python 3.12. The pong game should have nice looking graphics, and it should be a 2 player game. Make sure that there is an animation when players score. Also make sure that the score is calculated correctly. There should be a button to replay at the end. A round of play should last 30 seconds. The left player controls the paddle with W and S, the right player with the UP-ARROW and DOWN-ARROW. Over time the ball should be speeding up. Write the full game in a single python file.
ChatGPT

Ensuring constraints

I’m piecing together the constraints for the Pong game. Using Python 3.12 and Tkinter, it must feature graphics, a 2-player mode, scoring animations, and a replay button. Players control paddles with specific keys, and the ball speeds up over time.

Constructing the game

I’m thinking through the plan to create a Tkinter window for the game, draw paddles and a ball, bind keys for paddle movement, animate the ball, implement scoring with animations, display scores, and include a replay button with a 30-second time limit and increasing ball speed.

I’m crafting the full Pong game code in Python, using Tkinter for the GUI. Each feature will be well-commented for clarity.

Setting up the game

I’m focusing on importing tkinter, setting up the game window, defining paddles and ball, key bindings, and implementing a 30-second timer for each round.

Crafting the button

I’m coding the replay button, starting with importing tkinter. Ensuring all requirements are met, I’ll piece together each line of code, culminating in the final script.

python
import tkinter as tk import time class PongGame: def __init__(self, root): self.root = root self.root.title("Pong Game") # Game parameters self.width = 800 self.height = 400 self.paddle_width = 10 self.paddle_height = 100 self.ball_size = 20 self.ball_speed = 5 self.paddle_speed = 20 self.ball_speed_increment = 0.05 # Speed up over time self.game_duration = 30 # Round lasts 30 seconds # Initialize scores self.left_score = 0 self.right_score = 0 # Create canvas self.canvas = tk.Canvas(root, width=self.width, height=self.height, bg="black") self.canvas.pack() # Draw center line self.canvas.create_line(self.width/2, 0, self.width/2, self.height, fill="white") # Create paddles and ball self.left_paddle = self.canvas.create_rectangle( 10, (self.height - self.paddle_height)/2, 10 + self.paddle_width, (self.height + self.paddle_height)/2, fill="white" ) self.right_paddle = self.canvas.create_rectangle( self.width - 10 - self.paddle_width, (self.height - self.paddle_height)/2, self.width - 10, (self.height + self.paddle_height)/2, fill="white" ) self.ball = self.canvas.create_oval( (self.width - self.ball_size)/2, (self.height - self.ball_size)/2, (self.width + self.ball_size)/2, (self.height + self.ball_size)/2, fill="white" ) # Initialize movement variables self.left_paddle_move = 0 self.right_paddle_move = 0 self.ball_dx = self.ball_speed self.ball_dy = self.ball_speed # Bind keys self.root.bind("w", self.move_left_paddle_up) self.root.bind("s", self.move_left_paddle_down) self.root.bind("<Up>", self.move_right_paddle_up) self.root.bind("<Down>", self.move_right_paddle_down) # Initialize game over flag self.game_over = False # Start time self.start_time = time.time() # Display scores self.left_score_text = self.canvas.create_text(self.width/4, 20, text=f"{self.left_score}", font=("Arial", 24), fill="white") self.right_score_text = self.canvas.create_text(3*self.width/4, 20, text=f"{self.right_score}", font=("Arial", 24), fill="white") # Start the game loop self.game_loop() def move_left_paddle_up(self, event): self.left_paddle_move = -self.paddle_speed def move_left_paddle_down(self, event): self.left_paddle_move = self.paddle_speed def move_right_paddle_up(self, event): self.right_paddle_move = -self.paddle_speed def move_right_paddle_down(self, event): self.right_paddle_move = self.paddle_speed def game_loop(self): if not self.game_over: # Move paddles self.move_paddles() # Move ball self.move_ball() # Check for game over elapsed_time = time.time() - self.start_time if elapsed_time >= self.game_duration: self.end_game() else: # Increase ball speed over time self.ball_dx *= (1 + self.ball_speed_increment/100) self.ball_dy *= (1 + self.ball_speed_increment/100) # Call game_loop again after 20 ms self.root.after(20, self.game_loop) def move_paddles(self): # Move left paddle self.canvas.move(self.left_paddle, 0, self.left_paddle_move) # Keep paddle on screen left_paddle_pos = self.canvas.coords(self.left_paddle) if left_paddle_pos[1] < 0: self.canvas.move(self.left_paddle, 0, -left_paddle_pos[1]) elif left_paddle_pos[3] > self.height: self.canvas.move(self.left_paddle, 0, self.height - left_paddle_pos[3]) # Reset movement self.left_paddle_move = 0 # Move right paddle self.canvas.move(self.right_paddle, 0, self.right_paddle_move) # Keep paddle on screen right_paddle_pos = self.canvas.coords(self.right_paddle) if right_paddle_pos[1] < 0: self.canvas.move(self.right_paddle, 0, -right_paddle_pos[1]) elif right_paddle_pos[3] > self.height: self.canvas.move(self.right_paddle, 0, self.height - right_paddle_pos[3]) # Reset movement self.right_paddle_move = 0 def move_ball(self): # Move ball self.canvas.move(self.ball, self.ball_dx, self.ball_dy) ball_pos = self.canvas.coords(self.ball) # Top and bottom collision if ball_pos[1] <= 0 or ball_pos[3] >= self.height: self.ball_dy = -self.ball_dy # Left paddle collision if self.check_paddle_collision(self.left_paddle, ball_pos): self.ball_dx = abs(self.ball_dx) # Right paddle collision if self.check_paddle_collision(self.right_paddle, ball_pos): self.ball_dx = -abs(self.ball_dx) # Left wall collision (right player scores) if ball_pos[0] <= 0: self.right_score += 1 self.update_score() self.animate_score("Right Player Scores!") self.reset_ball() # Right wall collision (left player scores) if ball_pos[2] >= self.width: self.left_score += 1 self.update_score() self.animate_score("Left Player Scores!") self.reset_ball() def check_paddle_collision(self, paddle, ball_pos): paddle_pos = self.canvas.coords(paddle) if (ball_pos[2] >= paddle_pos[0] and ball_pos[0] <= paddle_pos[2]) and \ (ball_pos[3] >= paddle_pos[1] and ball_pos[1] <= paddle_pos[3]): return True return False def reset_ball(self): # Reset ball to center self.canvas.coords( self.ball, (self.width - self.ball_size)/2, (self.height - self.ball_size)/2, (self.width + self.ball_size)/2, (self.height + self.ball_size)/2 ) # Reverse ball direction self.ball_dx = -self.ball_dx self.ball_dy = self.ball_speed if self.ball_dy > 0 else -self.ball_speed def update_score(self): self.canvas.itemconfig(self.left_score_text, text=f"{self.left_score}") self.canvas.itemconfig(self.right_score_text, text=f"{self.right_score}") def animate_score(self, message): # Display a message temporarily text = self.canvas.create_text(self.width/2, self.height/2, text=message, font=("Arial", 36), fill="yellow") self.root.update() time.sleep(1) self.canvas.delete(text) def end_game(self): self.game_over = True # Display Game Over message winner = "Left Player Wins!" if self.left_score > self.right_score else "Right Player Wins!" if self.right_score > self.left_score else "It's a Tie!" self.canvas.create_text(self.width/2, self.height/2 - 30, text="Game Over", font=("Arial", 48), fill="red") self.canvas.create_text(self.width/2, self.height/2 + 30, text=winner, font=("Arial", 36), fill="white") # Create Replay button replay_button = tk.Button(self.root, text="Replay", command=self.restart_game) self.canvas.create_window(self.width/2, self.height/2 + 80, window=replay_button) def restart_game(self): # Reset scores self.left_score = 0 self.right_score = 0 self.update_score() # Reset ball and paddles self.reset_ball() self.canvas.coords( self.left_paddle, 10, (self.height - self.paddle_height)/2, 10 + self.paddle_width, (self.height + self.paddle_height)/2 ) self.canvas.coords( self.right_paddle, self.width - 10 - self.paddle_width, (self.height - self.paddle_height)/2, self.width - 10, (self.height + self.paddle_height)/2 ) # Remove Game Over text and Replay button self.canvas.delete("all") # Redraw elements self.canvas.create_line(self.width/2, 0, self.width/2, self.height, fill="white") self.left_paddle = self.canvas.create_rectangle( 10, (self.height - self.paddle_height)/2, 10 + self.paddle_width, (self.height + self.paddle_height)/2, fill="white" ) self.right_paddle = self.canvas.create_rectangle( self.width - 10 - self.paddle_width, (self.height - self.paddle_height)/2, self.width - 10, (self.height + self.paddle_height)/2, fill="white" ) self.ball = self.canvas.create_oval( (self.width - self.ball_size)/2, (self.height - self.ball_size)/2, (self.width + self.ball_size)/2, (self.height + self.ball_size)/2, fill="white" ) # Re-display scores self.left_score_text = self.canvas.create_text(self.width/4, 20, text=f"{self.left_score}", font=("Arial", 24), fill="white") self.right_score_text = self.canvas.create_text(3*self.width/4, 20, text=f"{self.right_score}", font=("Arial", 24), fill="white") # Reset variables self.ball_dx = self.ball_speed self.ball_dy = self.ball_speed self.game_over = False self.start_time = time.time() # Restart game loop self.game_loop() if __name__ == "__main__": root = tk.Tk() game = PongGame(root) root.mainloop()

This code creates a two-player Pong game using Python's built-in tkinter module. It includes:

  • Graphics: The game window displays paddles, a ball, and a center line on a canvas.
  • Controls:
    • Left player uses the W (up) and S (down) keys.
    • Right player uses the Up Arrow (up) and Down Arrow (down) keys.
  • Scoring and Animation: When a player scores, an animation displays a message for a short duration.
  • Timer: Each round lasts 30 seconds, after which the game ends, and a replay button appears.
  • Ball Speed Increase: The ball gradually speeds up over time.

To run the game, save the code in a file named pong_game.py and execute it with Python 3.12:

bash
python3.12 pong_game.py